#!/bin/bash
# seata 快捷docker安装运行
# 创建目录并移动脚本的函数
function dockerCreateStart() {
  name="$1"
  version="$2"
  asName="$3"
  portMap=$4
  volumesMap=$5
  dockerMap=$6
  copyDockerMap=$7
  lastDockerMap=$8
  #MYSQL_ROOT_PASSWORD=$9

  # 拉取 Docker 镜像（取消注释以启用）
  docker pull "${name}:${version}"

  # 删除同名容器
  docker rm -f "${asName}" &>/dev/null

  dockerRun="docker run "
  dockerRunTemp="docker run "

  if [ "${#portMap[@]}" -eq 0 ]; then
    echo ""
  else
    # 添加端口映射参数
    for element in "${portMap[@]}"; do
      dockerRun+="-p $element "
      dockerRunTemp+="-p $element "
    done
  fi

  if [ "${#dockerMap[@]}" -eq 0 ]; then
    echo ""
  else
    # 添加其他 Docker 参数
    for element in "${dockerMap[@]}"; do
      dockerRun+="$element "
      dockerRunTemp+="$element "
    done
  fi

  if [ "${#volumesMap[@]}" -eq 0 ]; then
    echo ""
  else
    # 添加卷映射参数
    for element in "${volumesMap[@]}"; do
      dockerRun+="-v $element "
    done
  fi

  dockerRun+="${name}:${version} "
  dockerRunTemp+="${name}:${version} "

  # 添加镜像及额外参数
  if [ "${#lastDockerMap[@]}" -eq 0 ]; then
    echo ""
  else
    for element in "${lastDockerMap[@]}"; do
      dockerRun+=" $element "
      dockerRunTemp+=" $element "
    done
  fi

  echo "$dockerRunTemp"
  eval "$dockerRunTemp"

  if [ "${#copyDockerMap[@]}" -eq 0 ]; then
    echo ""
  else
    echo "复制 开始"
    # 复制 Docker 映射文件
    for element in "${copyDockerMap[@]}"; do
      echo "复制 $element"
      IFS=':' read -r source dest <<<"$element"
      echo "docker cp ${asName}:${source} ${dest}"
      docker cp "${asName}":"${source}" "${dest}"
    done

    echo "复制 完成"
  fi

  # 删除同名容器
  docker rm -f "${asName}" &>/dev/null

  echo "正式启动挂载"
  echo "$dockerRun"
  eval "$dockerRun"
  #$dockerRun

  #  read -r -p "查看 $name 运行日志?【Y/N】" input
  #  if [[ "${input,,}" =~ ^(yes|y)$ ]]; then
  #      docker logs -f -t --tail=200 ${asName}
  #  else
  #      echo ""
  #  fi
}

function demo() {
  #nacos 文件配置
 seataServer.properties="#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
   #Transport configuration, for client and server
   transport.type=TCP
   transport.server=NIO
   transport.heartbeat=true
   transport.enableTmClientBatchSendRequest=false
   transport.enableRmClientBatchSendRequest=true
   transport.enableTcServerBatchSendResponse=false
   transport.rpcRmRequestTimeout=30000
   transport.rpcTmRequestTimeout=30000
   transport.rpcTcRequestTimeout=30000
   transport.threadFactory.bossThreadPrefix=NettyBoss
   transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
   transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
   transport.threadFactory.shareBossWorker=false
   transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
   transport.threadFactory.clientSelectorThreadSize=1
   transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
   transport.threadFactory.bossThreadSize=1
   transport.threadFactory.workerThreadSize=default
   transport.shutdown.wait=3
   transport.serialization=seata
   transport.compressor=none

   #Transaction routing rules configuration, only for the client
   service.vgroupMapping.default_tx_group=default
   #If you use a registry, you can ignore it
   service.default.grouplist=127.0.0.1:8091
   service.enableDegrade=false
   service.disableGlobalTransaction=false

   #Transaction rule configuration, only for the client
   client.rm.asyncCommitBufferLimit=10000
   client.rm.lock.retryInterval=10
   client.rm.lock.retryTimes=30
   client.rm.lock.retryPolicyBranchRollbackOnConflict=true
   client.rm.reportRetryCount=5
   client.rm.tableMetaCheckEnable=true
   client.rm.tableMetaCheckerInterval=60000
   client.rm.sqlParserType=druid
   client.rm.reportSuccessEnable=false
   client.rm.sagaBranchRegisterEnable=false
   client.rm.sagaJsonParser=fastjson
   client.rm.tccActionInterceptorOrder=-2147482648
   client.tm.commitRetryCount=5
   client.tm.rollbackRetryCount=5
   client.tm.defaultGlobalTransactionTimeout=60000
   client.tm.degradeCheck=false
   client.tm.degradeCheckAllowTimes=10
   client.tm.degradeCheckPeriod=2000
   client.tm.interceptorOrder=-2147482648
   client.undo.dataValidation=true
   client.undo.logSerialization=jackson
   client.undo.onlyCareUpdateColumns=true
   server.undo.logSaveDays=7
   server.undo.logDeletePeriod=86400000
   client.undo.logTable=undo_log
   client.undo.compress.enable=true
   client.undo.compress.type=zip
   client.undo.compress.threshold=64k
   #For TCC transaction mode
   tcc.fence.logTableName=tcc_fence_log
   tcc.fence.cleanPeriod=1h

   #Log rule configuration, for client and server
   log.exceptionRate=100

   #Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
   store.mode=file
   store.lock.mode=file
   store.session.mode=file
   #Used for password encryption
   store.publicKey=

   #If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
   store.file.dir=file_store/data
   store.file.maxBranchSessionSize=16384
   store.file.maxGlobalSessionSize=512
   store.file.fileWriteBufferCacheSize=16384
   store.file.flushDiskMode=async
   store.file.sessionReloadReadSize=100

   #These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
   store.db.datasource=druid
   store.db.dbType=mysql
   store.db.driverClassName=com.mysql.jdbc.Driver
   store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
   store.db.user=username
   store.db.password=password
   store.db.minConn=5
   store.db.maxConn=30
   store.db.globalTable=global_table
   store.db.branchTable=branch_table
   store.db.distributedLockTable=distributed_lock
   store.db.queryLimit=100
   store.db.lockTable=lock_table
   store.db.maxWait=5000

   #These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
   store.redis.mode=single
   store.redis.single.host=127.0.0.1
   store.redis.single.port=6379
   store.redis.sentinel.masterName=
   store.redis.sentinel.sentinelHosts=
   store.redis.maxConn=10
   store.redis.minConn=1
   store.redis.maxTotal=100
   store.redis.database=0
   store.redis.password=
   store.redis.queryLimit=100

   #Transaction rule configuration, only for the server
   server.recovery.committingRetryPeriod=1000
   server.recovery.asynCommittingRetryPeriod=1000
   server.recovery.rollbackingRetryPeriod=1000
   server.recovery.timeoutRetryPeriod=1000
   server.maxCommitRetryTimeout=-1
   server.maxRollbackRetryTimeout=-1
   server.rollbackRetryTimeoutUnlockEnable=false
   server.distributedLockExpireTime=10000
   server.xaerNotaRetryTimeout=60000
   server.session.branchAsyncQueueSize=5000
   server.session.enableBranchAsyncRemove=false
   server.enableParallelRequestHandle=false

   #Metrics configuration, only for the server
   metrics.enabled=false
   metrics.registryType=compact
   metrics.exporterList=prometheus
   metrics.exporterPrometheusPort=9898
   "
   mysqlSQL="
   -- 1. 执行语句创建名为 seata 的数据库
   CREATE DATABASE seata DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;

   -- 2.执行脚本完成 Seata 表结构的创建
   use seata;

   -- https://github.com/seata/seata/blob/1.7.1/script/server/db/mysql.sql
   -- -------------------------------- The script used when storeMode is 'db' --------------------------------
   -- the table to store GlobalSession data
   CREATE TABLE IF NOT EXISTS `global_table`
   (
       `xid`                       VARCHAR(128) NOT NULL,
       `transaction_id`            BIGINT,
       `status`                    TINYINT      NOT NULL,
       `application_id`            VARCHAR(32),
       `transaction_service_group` VARCHAR(32),
       `transaction_name`          VARCHAR(128),
       `timeout`                   INT,
       `begin_time`                BIGINT,
       `application_data`          VARCHAR(2000),
       `gmt_create`                DATETIME,
       `gmt_modified`              DATETIME,
       PRIMARY KEY (`xid`),
       KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
       KEY `idx_transaction_id` (`transaction_id`)
   ) ENGINE = InnoDB
     DEFAULT CHARSET = utf8mb4;

   -- the table to store BranchSession data
   CREATE TABLE IF NOT EXISTS `branch_table`
   (
       `branch_id`         BIGINT       NOT NULL,
       `xid`               VARCHAR(128) NOT NULL,
       `transaction_id`    BIGINT,
       `resource_group_id` VARCHAR(32),
       `resource_id`       VARCHAR(256),
       `branch_type`       VARCHAR(8),
       `status`            TINYINT,
       `client_id`         VARCHAR(64),
       `application_data`  VARCHAR(2000),
       `gmt_create`        DATETIME(6),
       `gmt_modified`      DATETIME(6),
       PRIMARY KEY (`branch_id`),
       KEY `idx_xid` (`xid`)
   ) ENGINE = InnoDB
     DEFAULT CHARSET = utf8mb4;

   -- the table to store lock data
   CREATE TABLE IF NOT EXISTS `lock_table`
   (
       `row_key`        VARCHAR(128) NOT NULL,
       `xid`            VARCHAR(128),
       `transaction_id` BIGINT,
       `branch_id`      BIGINT       NOT NULL,
       `resource_id`    VARCHAR(256),
       `table_name`     VARCHAR(32),
       `pk`             VARCHAR(36),
       `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
       `gmt_create`     DATETIME,
       `gmt_modified`   DATETIME,
       PRIMARY KEY (`row_key`),
       KEY `idx_status` (`status`),
       KEY `idx_branch_id` (`branch_id`),
       KEY `idx_xid` (`xid`)
   ) ENGINE = InnoDB
     DEFAULT CHARSET = utf8mb4;

   CREATE TABLE IF NOT EXISTS `distributed_lock`
   (
       `lock_key`       CHAR(20) NOT NULL,
       `lock_value`     VARCHAR(20) NOT NULL,
       `expire`         BIGINT,
       primary key (`lock_key`)
   ) ENGINE = InnoDB
     DEFAULT CHARSET = utf8mb4;

   INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
   INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
   INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
   INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);


   -- 日志
   CREATE TABLE IF NOT EXISTS `undo_log`
   (
       `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
       `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
       `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
       `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
       `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
       `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
       `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
       UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
   ) ENGINE = InnoDB
     AUTO_INCREMENT = 1
     DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
   "
  #SEATA_IP 宿主机地址
  docker run -d \
      --name seata \
      -p 8091:8091 \
      -p 7091:7091 \
      -e SEATA_IP=192.168.200.128 \
      -e SEATA_PORT=8091  \
      -v /docker-volumes/seata/8091/seata-server/resources/:/seata-server/resources/  \
      seataio/seata-server:1.7.1


  docker cp seata:/seata-server/  /docker-volumes/seata/8091/


}

# 创建目录并移动脚本的函数
function createStart() {
  local dockerVolumes="$1"
  local name="$2"
  local port="$3"
  local scriptName="${name}.sh"
  local destination="/${dockerVolumes}/${name}/${port}"
  rm -rf "${destination}"
  # 为脚本添加执行权限
  chmod +x "${scriptName}"

  # 使用 mkdir -p 创建父目录（如果不存在）
  mkdir -p "${destination}"

  # 删除已存在的脚本文件
  [ -f "/${dockerVolumes}/${name}/${scriptName}" ] && rm -rf "/${dockerVolumes}/${name}/${scriptName}"

  # 在移动之前检查脚本文件是否存在
  if [ -f "${scriptName}" ]; then
    cp "${scriptName}" "/${dockerVolumes}/${name}/"
    echo "脚本 '${scriptName}' 已复制到 '/${dockerVolumes}/${name}/'"
  else
    echo "错误：当前目录中找不到脚本 '${scriptName}'"
    read -r -p "继续 运行脚本?【Y/N】" input
    if [[ "${input,,}" =~ ^(yes|y)$ ]]; then
      echo "继续执行"
    else
      exit 1
    fi
  fi
}

function seata() {
  # 默认值
  networkName=$1
  dockerVolumes=$2
  #镜像名
  name=$3
  #别名
  asName=$4
  #版本
  version=$5
  port=$6

  #环境配置
  SEATA_IP=$7
  SEATA_PORT=8091
  #将容器  端口映射到宿主机的  端口
  portMap=("$port:$SEATA_PORT" "7091:7091")
  #挂载地址
  v0="/etc/localtime:/etc/localtime"
  v1="/$dockerVolumes/$asName/$port/seata-server/resources/:/seata-server/resources/"


  volumesMap=("$v0" "$v1" )

  dockerMap=("-d" "--name=${asName}" "--network=${networkName}")
  #dockerMap+=("--restart=always")
  dockerMap+=("-e SEATA_IP=$SEATA_IP")
  dockerMap+=("-e SEATA_PORT=$SEATA_PORT")
  cp1="/seata-server/:/$dockerVolumes/$asName/$port"
  copyDockerMap=($cp1)
  lastDockerMap=()
  echo "${asName} 初始化 启动 挂载..."
  createStart $dockerVolumes $asName $port
  dockerCreateStart "${name}" "${version}" "${asName}" $portMap $volumesMap $dockerMap $copyDockerMap $lastDockerMap
}
function main() {
  #参考文献：https://blog.csdn.net/u013737132/article/details/133376131
  # 默认值
  networkName="common-network"
  dockerVolumes="docker-volumes"
  #镜像名
  seataName="seataio/seata-server"
  #别名
  seataAsName="seata"
  #版本
  seataVersion="1.7.1"
  seataPortHost="8091"
  SEATA_IP=192.168.200.128
  docker network create $networkName
  seata $networkName $dockerVolumes $seataName $seataAsName $seataVersion $seataPortHost $SEATA_IP
}

main
